#include <Windows.h>
#include <tchar.h>
#include "resource.h"
#include <CommCtrl.h>

#define		WM_INITMONITOR		(WM_APP + 1000)

struct SMonitorInfo {
	int			nSize;
	TCHAR		szFilePath[MAX_PATH][32];
	HANDLE*		hHandles;
};

void RetrieveDriveName(TCHAR* szDriveName, TCHAR* szItem)
{
	if (NULL != szItem && NULL != szDriveName)
	{
		TCHAR* szPos = _tcsstr(szItem, _T(":\\"));
		if (NULL != szPos && szPos > szItem)
		{
			memcpy(szDriveName, --szPos, 3 * sizeof(TCHAR));
			szDriveName[3] = _T('\0');
		}
	}

	return;
}

DWORD CALLBACK ChangeMonitorProc(LPVOID lpData)
{
	SMonitorInfo* pMonitorInfo = (SMonitorInfo*)lpData;
	if (NULL != pMonitorInfo)
	{		
		while(true)
		{
			DWORD dwIndex = WaitForMultipleObjects(pMonitorInfo->nSize, pMonitorInfo->hHandles, FALSE, INFINITE) - WAIT_OBJECT_0;			
			
			if (0 == dwIndex)
			{
				break;
			} else {
				TCHAR szTmp[MAX_PATH];
				_stprintf(szTmp, _T("Driver(%s) has be modified\n"), pMonitorInfo->szFilePath[dwIndex]); 
			
				OutputDebugString(szTmp);
				FindNextChangeNotification(pMonitorInfo->hHandles[dwIndex]);
			}
		}

		for (int ii = 1; ii < pMonitorInfo->nSize; ii++)
		{
			if (NULL != pMonitorInfo->hHandles[ii])
			{
				FindCloseChangeNotification(pMonitorInfo->hHandles[ii]);
			}
		}
	}
	
	return 0;
}

int CALLBACK DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	static HANDLE hEvtQuit	= NULL;
	static HANDLE hThread	= NULL;
	static SMonitorInfo MonitorInfo;

	switch (nMsg)
	{
		case WM_INITDIALOG:
		{
			SetWindowText(hDlg, _T("Demo0064"));
			UINT nWidth		= GetSystemMetrics(SM_CXSCREEN);
			UINT nHeight	= GetSystemMetrics(SM_CYSCREEN);
			RECT rtClient;
			GetClientRect(hDlg, &rtClient);
			SetWindowPos(hDlg, NULL, (nWidth - (rtClient.right - rtClient.left)) / 2, (nHeight - (rtClient.bottom - rtClient.top)) / 2, 0, 0, SWP_NOSIZE);
			
			TCHAR szBuffer[MAX_PATH];
			GetLogicalDriveStrings(MAX_PATH, szBuffer);
			TCHAR* szPos = szBuffer;
			while (_T('\0') != *szPos)
			{
				TCHAR szDriveName[32];
				TCHAR szVolumeBuf[MAX_PATH];
				TCHAR szItemData[MAX_PATH];
				_tcscpy(szDriveName, szPos);
				GetVolumeInformation(szDriveName, szVolumeBuf, MAX_PATH, NULL, NULL, NULL, NULL, 0);
				_stprintf(szItemData, _T("%s - %s"), szDriveName, szVolumeBuf);
				SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_ADDSTRING, 0, (LPARAM)szItemData);
				
				szPos += _tcslen(szDriveName);
				szPos ++;
			}

			break;
		}
		case WM_INITMONITOR:
		{
			SetEvent(hEvtQuit);
			WaitForSingleObject(hThread, 3000);

			if (NULL != hEvtQuit)
			{
				CloseHandle(hEvtQuit);
				hEvtQuit = NULL;
			}
			
			if (NULL != MonitorInfo.hHandles)
			{
				delete[] MonitorInfo.hHandles;
				MonitorInfo.hHandles = NULL;
			}
			break;
		}
		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDC_BTNSTART:
				{
					TCHAR szBtnName[MAX_PATH];
					GetDlgItemText(hDlg, IDC_BTNSTART, szBtnName, MAX_PATH);
					if (0 == _tcsicmp(szBtnName, _T("Start")))
					{
						SetDlgItemText(hDlg, IDC_BTNSTART, _T("Stop"));
						SendMessage(hDlg, WM_INITMONITOR, 0, 0);

						TCHAR szItem[64];
						TCHAR szItemList[MAX_PATH][64];
						int nBuffer[MAX_PATH];
						int nSelCount		= SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_GETSELCOUNT, 0, 0);				
						SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_GETSELITEMS, (WPARAM)MAX_PATH, (LPARAM)nBuffer);
						DWORD dwFilter		= FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE;
				
						MonitorInfo.hHandles= new HANDLE[nSelCount + 1];
						MonitorInfo.nSize	= nSelCount + 1;
						MonitorInfo.hHandles[0]	= (hEvtQuit = CreateEvent(NULL, FALSE, FALSE, NULL));
						_tcscpy(MonitorInfo.szFilePath[0], _T("Quit"));
						for (int ii = 1; ii < nSelCount + 1; ii++)	
						{
							SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_GETTEXT, (WPARAM)nBuffer[ii - 1], (LPARAM)szItem);
							RetrieveDriveName(MonitorInfo.szFilePath[ii], szItem);			
							MonitorInfo.hHandles[ii] = FindFirstChangeNotification(MonitorInfo.szFilePath[ii], TRUE, dwFilter);	
						}
						hThread = CreateThread(NULL, NULL, ChangeMonitorProc, (LPVOID)&MonitorInfo, NULL, NULL);
					} else {
						SetDlgItemText(hDlg, IDC_BTNSTART, _T("Start"));
						SendMessage(hDlg, WM_INITMONITOR, 0, 0);
					}
					
					break;
				}
				case IDC_BTNEXIT:
				{
					SendMessage(hDlg, WM_INITMONITOR, 0, 0);
			
					EndDialog(hDlg, 0);
					break;
				}
			}
			break;
		}
		case WM_CLOSE:
		{
			PostQuitMessage(0);
			break;
		}
	}

	return 0;
}

BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);

	return TRUE;
}